package com.kmxd.ams.app.oss;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableSet;
import com.kmxd.ams.client.oss.IOssAttachmentSvc;
import com.kmxd.ams.client.oss.dto.OssAttachmentQueryDTO;
import com.kmxd.ams.client.oss.dto.OssAttachmentUploadDTO;
import com.kmxd.ams.client.oss.vo.OssAttachmentListVO;
import com.kmxd.ams.client.oss.vo.OssAttachmentVO;
import com.kmxd.ams.client.system.ISysConfigSvc;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.OssAttachmentTypeEnum;
import com.kmxd.ams.core.common.enums.OssEnum;
import com.kmxd.ams.core.common.enums.TransferStatusEnum;
import com.kmxd.ams.core.common.query.QueryGen;
import com.kmxd.ams.core.convert.DocConvertUtil;
import com.kmxd.ams.core.convert.impl.PdfService;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.oss.bo.OssFile;
import com.kmxd.ams.core.oss.template.OssTemplate;
import com.kmxd.ams.core.util.ConfigUtil;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.oss.entity.OssAttachment;
import com.kmxd.ams.infra.oss.mapper.OssAttachmentMapper;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

/**
 * 公共附件表 服务实现类
 *
 * @author ZuoLG
 * @since 2022-07-25
 */
@Slf4j
@Service
@AllArgsConstructor
public class OssAttachmentSvcImpl extends ServiceImpl<OssAttachmentMapper, OssAttachment>
    implements IOssAttachmentSvc {

  private final DocConvertUtil convertUtil;
  private OssTemplate ossTemplate;
  private ISysConfigSvc sysConfigSvc;

  @Override
  public Page<OssAttachmentListVO> selectPage(Page reqPage, OssAttachmentQueryDTO req) {
    LambdaQueryWrapper<OssAttachment> queryWrapper =
        QueryGen.init(new QueryWrapper<OssAttachment>(), req).lambda();
    Page<OssAttachment> page = this.baseMapper.selectPage(reqPage, queryWrapper);
    Page<OssAttachmentListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), OssAttachmentListVO.class));
    return voPage;
  }

  @Override
  public List<OssAttachmentListVO> selectList(OssAttachmentQueryDTO req) {
    LambdaQueryWrapper<OssAttachment> queryWrapper =
        QueryGen.init(new QueryWrapper<OssAttachment>(), req).lambda();
    List<OssAttachment> list = this.baseMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, OssAttachmentListVO.class);
  }

  @Override
  public List<OssAttachmentListVO> selectListByDay(OssAttachmentQueryDTO req) {
    LambdaQueryWrapper<OssAttachment> queryWrapper = Wrappers.lambdaQuery();
    String startTime = DateUtil.format(DateUtil.date(), "yyyy-MM-dd 00:00:00");
    String endTime = DateUtil.format(DateUtil.date(), "yyyy-MM-dd 23:59:59");
    queryWrapper.ge(OssAttachment::getUpdateTime, startTime);
    queryWrapper.le(OssAttachment::getUpdateTime, endTime);
    queryWrapper.ne(OssAttachment::getTransferStatus, TransferStatusEnum.S3.getCode());
    List<OssAttachment> list = this.baseMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, OssAttachmentListVO.class);
  }

  /**
   * 限制文件后缀
   *
   * @param fileName
   * @return
   */
  private boolean checkFileSuffix(String fileName) {
    boolean flag = false;
    String suffix = FileUtil.getSuffix(fileName);
    // 获取转换的文件类型
    String ossExtend = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_EXTEND);
    List<String> exts = StrUtil.split(ossExtend, "|");
    if (CollUtil.contains(exts, suffix)) {
      flag = true;
    }
    return flag;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public OssAttachmentVO upload(MultipartFile file) throws Exception {
    if (!checkFileSuffix(file.getOriginalFilename())) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "当前文件格式不支持上传！");
    }
    String path = DateUtil.format(DateUtil.date(), "yyyy/MM/dd");
    OssFile ossFile = ossTemplate.upload(file, OssEnum.attachment, path);
    OssAttachment entity = BeanUtil.copyProperties(ossFile, OssAttachment.class);
    entity.setShowFileName(ossFile.getName());
    entity.setStatus(true);
    entity.setFondsId(SecurityUtil.getFondsId());
    entity.setComId(SecurityUtil.getCropId());
    entity.setTransferStatus(1L);
    entity.setDefPath(ossTemplate.getDefPath());
    this.baseMapper.insert(entity);
    return BeanUtil.copyProperties(entity, OssAttachmentVO.class);
  }

  @Override
  public OssAttachmentVO upload(MultipartFile file, OssAttachmentUploadDTO req) throws Exception {
    if (!checkFileSuffix(file.getOriginalFilename())) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "当前文件格式不支持上传！");
    }
    String path = DateUtil.format(DateUtil.date(), "yyyy/MM/dd");
    req.setPath(ObjectUtil.isNotEmpty(req.getPath()) ? req.getPath() : path);
    OssFile ossFile = ossTemplate.upload(file, OssEnum.attachment, req.getPath());
    OssAttachment entity = BeanUtil.copyProperties(req, OssAttachment.class);
    BeanUtil.copyProperties(ossFile, entity, CopyOptions.create().ignoreNullValue());
    entity.setShowFileName(file.getOriginalFilename());
    entity.setStatus(true);
    entity.setFondsId(SecurityUtil.getFondsId());
    entity.setComId(SecurityUtil.getCropId());
    entity.setTransferStatus(1L);
    entity.setDefPath(ossTemplate.getDefPath());
    this.baseMapper.insert(entity);
    if (ImmutableSet.of(OssAttachmentTypeEnum.USE.getType(), OssAttachmentTypeEnum.NOTICE.getType())
        .contains(entity.getType())) {
      efileConvert(entity);
    }
    return BeanUtil.copyProperties(entity, OssAttachmentVO.class);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    idList.forEach(
        item -> {
          OssAttachmentVO attachment = view(item);
          if (ObjectUtil.isNotNull(attachment)) {
            ossTemplate.delete(attachment.getRootPath() + attachment.getPath());
          }
          this.baseMapper.deleteById(item);
        });
  }

  @Override
  public OssAttachmentVO view(Long id) {
    OssAttachment entity = this.baseMapper.selectById(id);
    return BeanUtil.copyProperties(entity, OssAttachmentVO.class);
  }

  @Override
  public OssAttachmentVO download(Long id) {
    OssAttachmentVO view = view(id);
    File file = ossTemplate.getFile(view.getRootPath() + view.getPath());
    view.setFile(file);
    return view;
  }

  @Override
  public OssAttachmentVO preview(Long id) {
    try {
      OssAttachmentVO view = view(id);
      // 转换成功的直接返回
      if (ObjectUtil.equals(TransferStatusEnum.S3.getCode(), view.getTransferStatus())) {
        File file = ossTemplate.getFile(view.getRootPath() + view.getTransferPath());
        view.setFile(file);
      } else {
        // 其他状态
        efileConvert(ConvertUtil.toBean(view, OssAttachment.class));
        File file = ossTemplate.getFile(view.getRootPath() + view.getTransferPath());
        view.setFile(file);
      }
      return view;
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return new OssAttachmentVO();
    }
  }

  /**
   * 转换
   *
   * @param attachment
   * @throws Exception
   */
  @Transactional(rollbackFor = Exception.class)
  public void efileConvert(OssAttachment attachment) throws Exception {
    log.debug("attachment: {} ", attachment.toString());
    fileOpt(attachment);
  }

  /**
   * 文件转换操作
   *
   * @param attachment
   */
  private void fileOpt(OssAttachment attachment) {
    // 获取转换的文件类型
    String fileTypeConf = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_FILE_TYPE);
    // 获取转换方式
    String transferConf = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_TRANSFER);
    // 转换后缀
    String transferExt = ConfigUtil.getVal(transferConf, ConfigConst.TRANSFER_EXT);
    // 转换方式
    String transferType = ConfigUtil.getVal(transferConf, ConfigConst.TRANSFER_TYPE);
    // 转换Url
    String transferURL = ConfigUtil.getVal(transferConf, ConfigConst.TRANSFER_URL);
    // 设置支持的格式
    if (ObjectUtil.isNotNull(fileTypeConf)) {
      List<String> words = ConfigUtil.getStrs(fileTypeConf, "word");
      List<String> excels = ConfigUtil.getStrs(fileTypeConf, "excel");
      List<String> ppts = ConfigUtil.getStrs(fileTypeConf, "ppt");
      List<String> pdfs = ConfigUtil.getStrs(fileTypeConf, "pdf");
      List<String> imgs = ConfigUtil.getStrs(fileTypeConf, "img");
      List<String> htmls = ConfigUtil.getStrs(fileTypeConf, "html");
      List<String> tiffs = ConfigUtil.getStrs(fileTypeConf, "tiff");
      convertUtil.init(transferType).setFileType(words, PdfService.TYPE_WORD);
      convertUtil.init(transferType).setFileType(excels, PdfService.TYPE_EXCEL);
      convertUtil.init(transferType).setFileType(ppts, PdfService.TYPE_PPT);
      convertUtil.init(transferType).setFileType(pdfs, PdfService.TYPE_PDF);
      convertUtil.init(transferType).setFileType(imgs, PdfService.TYPE_IMG);
      convertUtil.init(transferType).setFileType(htmls, PdfService.TYPE_HTML);
      convertUtil.init(transferType).setFileType(tiffs, PdfService.TYPE_TIFF);
    }
    try {
      String basePath = attachment.getRootPath();
      String srcPath = basePath + attachment.getPath();
      // 判断文件是否存在 "装换状态：1待处理，2转换中，3成功，4失败，99不支持转换，0不需要转换"
      attachment.setTransferStatus(
          FileUtil.exist(srcPath)
              ? TransferStatusEnum.S2.getCode()
              : TransferStatusEnum.S4.getCode());

      String pdfPath =
          attachment.getPath().substring(0, attachment.getPath().lastIndexOf('.'))
              + "."
              + transferExt;

      attachment.setShowFileName(attachment.getName());
      attachment.setTransferPath(pdfPath);
      // 根据类型转换执行不同的转换,转换方式：aspose|shuke|youhong
      // 执行文件转换
      convertUtil.init(transferType).docConvert(srcPath, basePath + pdfPath);
      attachment.setTransferStatus(TransferStatusEnum.S3.getCode());
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      attachment.setTransferStatus(TransferStatusEnum.S4.getCode());
      attachment.setUpdateTime(new Date());
    }
    updateById(attachment);
  }
}
